#include "evm_module.h"

static evm_val_t evm_module_builtin_toJsArray(evm_t *e, evm_val_t *p, int argc, evm_val_t *v)
{
    EVM_UNUSED(p);
    if(argc != 2) return EVM_VAL_UNDEFINED;
    if(!evm_is_invoke(v) || !evm_is_integer(v+1)) return EVM_VAL_UNDEFINED;

    int len = evm_2_integer(v+1);
    evm_val_t *buffer = evm_buffer_create(e, len);
    uint8_t *addr = evm_buffer_addr(buffer);
    memcpy(addr, (char *)evm_2_intptr(v), len);
    return *buffer;
}

static evm_val_t evm_module_builtin_toJsString(evm_t *e, evm_val_t *p, int argc, evm_val_t *v)
{
    EVM_UNUSED(p);
    if(argc != 2) return EVM_VAL_UNDEFINED;
    if(!evm_is_invoke(v) || !evm_is_integer(v+1)) return EVM_VAL_UNDEFINED;

    evm_val_t *str = evm_heap_string_create(e, (char *)evm_2_intptr(v), evm_2_integer(v+1));
    if(str == NULL)
        return EVM_VAL_UNDEFINED;
    return *str;
}

//sys.copy(dest, src, len)
static evm_val_t evm_module_builtin_copy(evm_t *e, evm_val_t *p, int argc, evm_val_t *v)
{
    EVM_UNUSED(e);
    EVM_UNUSED(p);
    if(argc != 3)
        return EVM_VAL_FALSE;

    if(!evm_is_invoke(v) || !evm_is_number(v+2))
        return EVM_VAL_FALSE;

    char *addr = (char *)evm_2_intptr(v);
    if(addr == NULL)
        return EVM_VAL_FALSE;

    uint32_t len = evm_2_integer(v+2);

    if(evm_is_list(v+1)){
        if(len > evm_list_len(v+1))
            len = evm_list_len(v+1);
        for(uint32_t i=0; i<len; i++){
            evm_val_t *data = evm_list_get(e,v+1,i);
            if(data == NULL)
                return EVM_VAL_FALSE;
            if(!evm_is_number(data))
                return EVM_VAL_FALSE;
            int buff = evm_2_integer(data);
            addr[i] = buff;
        }
    }else if(evm_is_buffer(v+1)){
        if(len >= evm_buffer_len(v+1))
            len = evm_buffer_len(v+1);
        memcpy(addr, evm_buffer_addr(v+1), len);
    }else if(evm_is_string(v+1))
    {
        if(len >= evm_string_len(v+1))
            len = evm_string_len(v+1);
        memcpy(addr, evm_2_string(v+1), len);
    }
    return EVM_VAL_TRUE;
}

/**
 * @brief  evm_module_system_malloc
 * @note   申请内存
 * @param  size: 申请大小
 * @retval 内存地址
 */
static void *evm_module_builtin_malloc(ssize_t size){
    return evm_malloc(size);
}

/**
 * @brief  evm_module_system_free
 * @note   释放内存
 * @param  *ptr: 内存地址
 * @retval None
 */
static void evm_module_builtin_free(void * ptr){
    evm_free(ptr);
}

evm_err_t evm_module_builtin(evm_t *e){
    evm_cffi_t funcs[] = {
        {"malloc", (uintptr_t)evm_module_builtin_malloc, "pi"},
        {"free", (uintptr_t)evm_module_builtin_free, "vp"},
        {NULL, 0, NULL}
    };

    evm_builtin_t builtin[] = {
        {"toJsArray", evm_mk_native((intptr_t)evm_module_builtin_toJsArray)},
        {"toJsString", evm_mk_native((intptr_t)evm_module_builtin_toJsString)},
        {"copy", evm_mk_native((intptr_t)evm_module_builtin_copy)},
        {NULL, EVM_VAL_UNDEFINED}
    };

    evm_module_effi_create(e, "@native.builtin", funcs , builtin);
    return e->err;
}
